<template>
    <div>
        <el-drawer v-bind="$attrs" v-on="$listeners" @opened="onOpen" @close="onClose">
            <div style="height:100%">
                <el-row style="height:100%;overflow:auto">
                    <el-col :md="24" :lg="12" class="left-editor">
                        <div class="setting" title="资源引用" @click="showResource">
                            <el-badge :is-dot="!!resources.length" class="item">
                                <i class="el-icon-setting"/>
                            </el-badge>
                        </div>
                        <el-tabs v-model="activeTab" type="card" class="editor-tabs">
                            <el-tab-pane name="html">
                                <span slot="label">
                                  <i v-if="activeTab==='html'" class="el-icon-edit"/>
                                  <i v-else class="el-icon-document"/>
                                  template
                                </span>
                            </el-tab-pane>
                            <el-tab-pane name="js">
                                <span slot="label">
                                  <i v-if="activeTab==='js'" class="el-icon-edit"/>
                                  <i v-else class="el-icon-document"/>
                                  script
                                </span>
                            </el-tab-pane>
                            <el-tab-pane name="css">
                                <span slot="label">
                                  <i v-if="activeTab==='css'" class="el-icon-edit"/>
                                  <i v-else class="el-icon-document"/>
                                  css
                                </span>
                            </el-tab-pane>
                        </el-tabs>
                        <div v-show="activeTab==='html'" id="editorHtml" class="tab-editor">
                            <MonacoEditor
                                    class="editor"
                                    v-model="editorHtml.code"
                                    :language="editorHtml.language"
                                    :theme="editorHtml.theme"
                                    :options="editorHtml.options"
                            />
                        </div>
                        <div v-show="activeTab==='js'" id="editorJs" class="tab-editor">
                            <MonacoEditor
                                    class="editor"
                                    v-model="editorJs.code"
                                    :language="editorJs.language"
                                    :theme="editorJs.theme"
                                    :options="editorJs.options"
                            />
                        </div>
                        <div v-show="activeTab==='css'" id="editorCss" class="tab-editor">
                            <MonacoEditor
                                    class="editor"
                                    v-model="editorCss.code"
                                    :language="editorCss.language"
                                    :theme="editorCss.theme"
                                    :options="editorCss.options"
                            />
                        </div>
                    </el-col>
                    <el-col :md="24" :lg="12" class="right-preview">
                        <div class="action-bar" :style="{'text-align': 'left'}">
                          <span class="bar-btn" @click="runCode">
                                <i class="el-icon-refresh"/>
                                刷新
                          </span>
                            <span class="bar-btn" @click="exportFile">
                                <i class="el-icon-download"/>
                                导出vue文件
                          </span>
                            <span ref="copyBtn" class="bar-btn copy-btn">
                                <i class="el-icon-document-copy"/>
                                复制代码
                            </span>
                            <span class="bar-btn delete-btn" @click="$emit('update:visible', false)">
                                    <i class="el-icon-circle-close"/>
                                    关闭
                              </span>
                        </div>
                        <iframe
                                v-show="isIframeLoaded"
                                ref="previewPage"
                                class="result-wrapper"
                                frameborder="0"
                                src="preview.html"
                                @load="iframeLoad"
                        />
                        <div v-show="!isIframeLoaded" v-loading="true" class="result-wrapper"/>
                    </el-col>
                </el-row>
            </div>
        </el-drawer>
        <resource-dialog
                :visible.sync="resourceVisible"
                :origin-resource="resources"
                @save="setResource"
        />
    </div>
</template>
<script>
    import MonacoEditor from 'vue-monaco'
    import beautifier from 'js-beautify'
    import {parse} from '@babel/parser'
    import ClipboardJS from 'clipboard'
    import {saveAs} from 'file-saver'
    import {
        makeUpHtml, vueTemplate, vueScript, cssStyle
    } from './generator/html'
    import {makeUpJs} from './generator/js'
    import {makeUpCss} from './generator/css'
    import {exportDefault, beautifierConf, titleCase} from './utils/index'
    import ResourceDialog from './ResourceDialog'
    const editorObj = {
        html: null,
        js: null,
        css: null
    }

    export default {
        components: {
            ResourceDialog,
            MonacoEditor
        },
        props: ['formData', 'generateConf'],
        data() {
            return {
                activeTab: 'html',
                htmlCode: '',
                jsCode: '',
                cssCode: '',
                codeFrame: '',
                isIframeLoaded: false,
                isInitcode: false, // 保证open后两个异步只执行一次runcode
                isRefreshCode: false, // 每次打开都需要重新刷新代码
                resourceVisible: false,
                scripts: [],
                links: [],
                monaco: null,
                editorHtml: {
                    code: '',
                    language: 'html',
                    theme: 'vs-dark',
                    options: {
                        automaticLayout: true
                    }
                },
                editorJs: {
                    code: '',
                    language: 'javascript',
                    theme: 'vs-dark',
                    options: {
                        automaticLayout: true
                    }
                },
                editorCss: {
                    code: '',
                    language: 'css',
                    theme: 'vs-dark',
                    options: {
                        automaticLayout: true
                    }
                },
            }
        },
        computed: {
            resources() {
                return this.scripts.concat(this.links)
            }
        },
        watch: {},
        created() {
        },
        mounted() {
            window.addEventListener('keydown', this.preventDefaultSave)
            const clipboard = new ClipboardJS('.copy-btn', {
                text: trigger => {
                    const codeStr = this.generateCode()
                    this.$notify({
                        title: '成功',
                        message: '代码已复制到剪切板，可粘贴。',
                        type: 'success'
                    })
                    return codeStr
                }
            })
            clipboard.on('error', e => {
                this.$message.error('代码复制失败')
            })
        },
        beforeDestroy() {
            window.removeEventListener('keydown', this.preventDefaultSave)
        },
        methods: {
            preventDefaultSave(e) {
                if (e.key === 's' && (e.metaKey || e.ctrlKey)) {
                    e.preventDefault()
                }
            },
            onOpen() {
                debugger;
                const {type} = this.generateConf
                this.htmlCode = makeUpHtml(this.formData, type)
                this.jsCode = makeUpJs(this.formData, type)
                this.cssCode = makeUpCss(this.formData)

                this.editorHtml = {
                    ...this.editorHtml,
                    code: beautifier.html(this.htmlCode, beautifierConf.html)
                }
                this.editorJs = {
                    ...this.editorJs,
                    code: beautifier.js(this.jsCode, beautifierConf.js)
                }

                this.editorCss = {
                    ...this.editorCss,
                    code: beautifier.css(this.cssCode, beautifierConf.css)
                }

                if (!this.isInitcode) {
                    this.isRefreshCode = true
                    this.isIframeLoaded && (this.isInitcode = true) && this.runCode()
                }
            },
            onClose() {
                this.isInitcode = false
                this.isRefreshCode = false
                this.isIframeLoaded = false
            },
            iframeLoad() {
                debugger;
                if (!this.isInitcode) {
                    this.isIframeLoaded = true
                    this.isRefreshCode && (this.isInitcode = true) && this.runCode()
                }
            },
            /*setEditorValue(id, type, codeStr) {
                if (editorObj[type]) {
                    editorObj[type].setValue(codeStr)
                } else {
                    editorObj[type] = monaco.editor.create(document.getElementById(id), {
                        value: codeStr,
                        theme: 'vs-dark',
                        language: mode[type],
                        automaticLayout: true
                    })
                }
                // ctrl + s 刷新
                editorObj[type].onKeyDown(e => {
                    if (e.keyCode === 49 && (e.metaKey || e.ctrlKey)) {
                        this.runCode()
                    }
                })
            },*/
            runCode() {
                debugger;
                //const jsCodeStr = editorObj.js.getValue()
                try {
                    const ast = parse(this.jsCode, {sourceType: 'module'})
                    const astBody = ast.program.body
                    if (astBody.length > 1) {
                        this.$confirm(
                            'js格式不能识别，仅支持修改export default的对象内容',
                            '提示',
                            {
                                type: 'warning'
                            }
                        )
                        return
                    }
                    if (astBody[0].type === 'ExportDefaultDeclaration') {
                        const postData = {
                            type: 'refreshFrame',
                            data: {
                                generateConf: this.generateConf,
                                html: this.htmlCode,
                                js: this.jsCode.replace(exportDefault, ''),
                                css: this.cssCode,
                                scripts: this.scripts,
                                links: this.links
                            }
                        }

                        this.$refs.previewPage.contentWindow.postMessage(
                            postData,
                            location.origin
                        )
                    } else {
                        this.$message.error('请使用export default')
                    }
                } catch (err) {
                    this.$message.error(`js错误：${err}`)
                    console.error(err)
                }
            },
            generateCode() {
                const html = vueTemplate(editorObj.html.getValue())
                const script = vueScript(editorObj.js.getValue())
                const css = cssStyle(editorObj.css.getValue())
                return beautifier.html(html + script + css, beautifierConf.html)
            },
            exportFile() {
                this.$prompt('文件名:', '导出文件', {
                    inputValue: `${+new Date()}.vue`,
                    closeOnClickModal: false,
                    inputPlaceholder: '请输入文件名'
                }).then(({value}) => {
                    if (!value) value = `${+new Date()}.vue`
                    const codeStr = this.generateCode()
                    const blob = new Blob([codeStr], {type: 'text/plain;charset=utf-8'})
                    saveAs(blob, value)
                })
            },
            showResource() {
                this.resourceVisible = true
            },
            setResource(arr) {
                const scripts = [];
                const
                    links = []
                if (Array.isArray(arr)) {
                    arr.forEach(item => {
                        if (item.endsWith('.css')) {
                            links.push(item)
                        } else {
                            scripts.push(item)
                        }
                    })
                    this.scripts = scripts
                    this.links = links
                } else {
                    this.scripts = []
                    this.links = []
                }
            }
        }
    }
</script>

<style lang="scss" scoped>
    @import './styles/mixin.scss';

    .tab-editor {
        position: absolute;
        top: 33px;
        bottom: 0;
        left: 0;
        right: 0;
        font-size: 14px;
        .editor {
            height: 100%;
            width: 100%;
        }
    }

    .left-editor {
        position: relative;
        height: 100%;
        background: #1e1e1e;
        overflow: hidden;
    }

    .setting {
        position: absolute;
        right: 15px;
        top: 3px;
        color: #a9f122;
        font-size: 18px;
        cursor: pointer;
        z-index: 1;
    }

    .right-preview {
        height: 100%;
        .result-wrapper {
            height: calc(100vh - 33px);
            width: 100%;
            overflow: auto;
            padding: 12px;
            box-sizing: border-box;
        }
    }

    @include action-bar;
    ::v-deep .el-drawer__header {
        display: none;
    }
</style>
